package com.sky.service.impl;

import com.alibaba.fastjson.JSON;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.sky.constant.MessageConstant;
import com.sky.context.BaseContext;
import com.sky.dto.*;
import com.sky.entity.*;
import com.sky.exception.OrderBusinessException;
import com.sky.mapper.*;
import com.sky.result.PageResult;
import com.sky.result.Result;
import com.sky.service.OrderService;
import com.sky.service.ShoppingCartService;
import com.sky.utils.WeChatPayUtil;
import com.sky.vo.*;
import com.sky.websocket.WebSocketServer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.*;

@Slf4j
@Service
public class OrderServiceImpl implements OrderService {
    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private ShoppingCartMapper shoppingCartMapper;
    @Autowired
    private AddressBookMapper addressBookMapper;
    @Autowired
    private ShoppingCartService shoppingCartService;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private OrderDetailMapper orderDetailMapper;
//    @Autowired
//    private WeChatPayUtil weChatPayUtil;
    @Autowired
    private WebSocketServer webSocketServer;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<OrderSubmitVO> submit(OrdersSubmitDTO ordersSubmitDTO) {
        //处理各种业务异常(地址簿为空，购物车为空)
        AddressBook addressBook = AddressBook
                .builder()
                .id(ordersSubmitDTO.getAddressBookId())
                .userId(BaseContext.getCurrentId())
                .build();
        AddressBook address = addressBookMapper.getAddress(addressBook);
        if (address == null) {
            return Result.error(MessageConstant.ADDRESS_BOOK_IS_NULL);
        }
        ShoppingCart shoppingCart =ShoppingCart
                .builder()
                .userId(BaseContext.getCurrentId())
                .build();
        List<ShoppingCart> shoppingCartList = shoppingCartMapper.getGoodsExsist(shoppingCart);
        if (CollectionUtils.isEmpty(shoppingCartList)) {
            return Result.error(MessageConstant.SHOPPING_CART_IS_NULL);
        }
        //向订单表插入1条数据
        //组装用户默认地址
        String userAddress=address.getProvinceName()+address.getCityName()+address.getDistrictName()+address.getDetail();
        //获取用户姓名
        User user=userMapper.getbyId(BaseContext.getCurrentId());
        String number = String.valueOf(System.currentTimeMillis());
        Orders order=Orders
                .builder()
                .userId(BaseContext.getCurrentId())
                .payStatus(Orders.UN_PAID) //支付状态
                .status(Orders.PENDING_PAYMENT) //订单状态
                .payMethod(ordersSubmitDTO.getPayMethod())
                .number(number) //订单号
                .orderTime(LocalDateTime.now()) //下单时间
                .addressBookId(address.getId())
                .amount(ordersSubmitDTO.getAmount())
                .remark(ordersSubmitDTO.getRemark())
                .phone(address.getPhone())
                .address(userAddress)
                .userName(user.getName())
                .consignee(address.getConsignee())
                .estimatedDeliveryTime(ordersSubmitDTO.getEstimatedDeliveryTime())
                .deliveryStatus(ordersSubmitDTO.getDeliveryStatus())
                .packAmount(ordersSubmitDTO.getPackAmount())
                .tablewareNumber(ordersSubmitDTO.getTablewareNumber())
                .tablewareStatus(ordersSubmitDTO.getTablewareStatus())
                .build();
        orderMapper.insert(order);
        Orders orders=orderMapper.getByNumber(number);
        if(orders==null){
            return Result.error(MessageConstant.ORDER_NOT_FOUND);
        }
        List<OrderDetail> orderDetailList = new ArrayList<>();
        //订单添加成功,向订单详情表插入n条数据
        for (ShoppingCart cart : shoppingCartList) {
            OrderDetail orderDetail= OrderDetail
                    .builder()
                    .name(cart.getName())
                    .image(cart.getImage())
                    .orderId(orders.getId())
                    .dishId(cart.getDishId())
                    .dishFlavor(cart.getDishFlavor())
                    .setmealId(cart.getSetmealId())
                    .number(cart.getNumber())
                    .amount(cart.getAmount())
                    .build();
            orderDetailList.add(orderDetail);
        }
        int insertResult=orderDetailMapper.BatchInsert(orderDetailList);
        if(insertResult>0){
            //清空购物车数据
            shoppingCartService.clean();
        }
        //封装VO
        OrderSubmitVO orderSubmitVO=OrderSubmitVO
                .builder()
                .id(orders.getId())
                .orderTime(orders.getOrderTime())
                .orderAmount(orders.getAmount())
                .orderNumber(orders.getNumber())
                .build();
        return Result.success(orderSubmitVO);
    }
    /**
     * 订单支付
     *
     * @param ordersPaymentDTO
     * @return
     */
    public Result<Map<String,LocalDateTime>> payment(OrdersPaymentDTO ordersPaymentDTO) throws Exception {
//        // 当前登录用户id
//        Long userId = BaseContext.getCurrentId();
//        User user = userMapper.getbyId(userId);
//
//        //调用微信支付接口，生成预支付交易单
//        JSONObject jsonObject = weChatPayUtil.pay(
//                ordersPaymentDTO.getOrderNumber(), //商户订单号
//                new BigDecimal(0.01), //支付金额，单位 元
//                "苍穹外卖订单", //商品描述
//                user.getOpenid() //微信用户的openid
//        );
//
//        if (jsonObject.getString("code") != null && jsonObject.getString("code").equals("ORDERPAID")) {
//            throw new OrderBusinessException("该订单已支付");
//        }
//
//        OrderPaymentVO vo = jsonObject.toJavaObject(OrderPaymentVO.class);
//        vo.setPackageStr(jsonObject.getString("package"));

//        return Result.success(ordersPaymentDTO.getOrderNumber());

        Orders orders = orderMapper.getByNumber(ordersPaymentDTO.getOrderNumber());
        if(orders==null){
            return Result.error(MessageConstant.ORDER_NOT_FOUND);
        }
        LocalDateTime estimatedDeliveryTime = paySuccess(orders,ordersPaymentDTO.getPayMethod());
        Map<String,LocalDateTime> map=new HashMap<>();
        map.put("estimatedDeliveryTime",estimatedDeliveryTime);
        //通过websocket向客户端浏览器推送消息 type orderId content
        Map map1=new HashMap<>();
        map1.put("type",1);
        map1.put("orderId",orders.getId());
        map1.put("content","订单号:"+ordersPaymentDTO.getOrderNumber());
        String json = JSON.toJSONString(map1);
        webSocketServer.sendToAllClient(json);
        return Result.success(map);
    }

    /**
     * 支付成功，修改订单状态
     */
    public LocalDateTime paySuccess(Orders orders,Integer payMethod) throws Exception {

        // 根据订单id更新订单的状态、支付方式、支付状态、结账时间
        Orders order = Orders.builder()
                .id(orders.getId())
                .status(Orders.TO_BE_CONFIRMED)
                .payStatus(Orders.PAID)
                .payMethod(payMethod)
                .checkoutTime(LocalDateTime.now())
                .build();
        orderMapper.update(order);


        return orders.getEstimatedDeliveryTime();
    }

    @Override
    public Result<OrdersDetailVO> getOrderDetail(Long orderId) {
        //定义响应数据
        OrdersDetailVO ordersDetailVO=new OrdersDetailVO();
        //根据订单id和用户Id查询订单
        Orders orders = orderMapper.getOrder(orderId,BaseContext.getCurrentId());
        BeanUtils.copyProperties(orders,ordersDetailVO);
        //根据订单id查询订单详情信息
        List<OrderDetail> orderDetailList=orderDetailMapper.getOrderDetail(orderId,null);
        ordersDetailVO.setOrderDetailList(orderDetailList);
        return Result.success(ordersDetailVO);
    }

    @Override
    public Result reminder(Long orderId) {
        /**
         * 催单任务待完成
         */
        //根据 id 查询订单
        Orders ordersDB = orderMapper.getOrder(orderId,BaseContext.getCurrentId());

        //校验订单是否存在，并且状态为4
        if (ordersDB == null) {
            throw new OrderBusinessException(MessageConstant.ORDER_STATUS_ERROR);
        }

        Map map = new HashMap();
        map.put("type", 2);  // 1 表示来单提醒， 2 客户催单
        map.put("orderId", orderId);
        map.put("content", "订单号:" + ordersDB.getNumber());
        //通过 websocket 向客户端浏览器推送消息
        webSocketServer.sendToAllClient(JSON.toJSONString(map));
        //log.trace("催单任务待完成");
        return Result.success();
    }

    /**
     * 再来一单就是将原订单中的商品重新加入到购物车中
     * @param orderId
     * @return
     */
    @Override
    public Result repetition(Long orderId) {
        Orders order = orderMapper.getOrder(orderId, BaseContext.getCurrentId());
        if(order==null){
            return Result.error(MessageConstant.ORDER_NOT_FOUND);
        }
        List<OrderDetail> orderDetail = orderDetailMapper.getOrderDetail(orderId,null);
        if(CollectionUtils.isEmpty(orderDetail)){
            return Result.error("该订单中没有商品");
        }
        //定义购物车对象,用于向购物车表批量添加数据
        List<ShoppingCart> shoppingCartList=new ArrayList<>();
        for (OrderDetail detail : orderDetail) {
            ShoppingCart shoppingCart=ShoppingCart
                    .builder()
                    .name(detail.getName())
                    .userId(BaseContext.getCurrentId())
                    .image(detail.getImage())
                    .dishId(detail.getDishId())
                    .dishFlavor(detail.getDishFlavor())
                    .setmealId(detail.getSetmealId())
                    .number(detail.getNumber())
                    .amount(detail.getAmount())
                    .createTime(LocalDateTime.now())
                    .build();
            shoppingCartList.add(shoppingCart);
        }
        int insertResult=shoppingCartMapper.BatchInsert(shoppingCartList);
        if(insertResult>0){
            return Result.success();
        }else{
            return Result.error("订单详情信息回调购物车失败");
        }
    }

    @Override
    public Result<PageResult> pageQueryOrders(Integer pageSize,Integer page,Integer status) {
        //定义分页响应数据
        PageResult pageResult=new PageResult();
        //定义分页后的订单数据
        List<OrdersDetailVO> orders=new ArrayList<OrdersDetailVO>();
        //开启分页
        PageHelper.startPage(page,pageSize);
        //调用数据库查询所有订单信息
        Orders wapper=Orders.builder().status(status).userId(BaseContext.getCurrentId()).build();
        Page<OrdersDetailVO> ordersData=orderMapper.getOrders(wapper);
        //获取分页后的订单和订单详情表信息
        List<OrdersDetailVO> ordersList = ordersData.getResult();
        for (OrdersDetailVO order : ordersList) {
            //调用mapper获取订单详情表数据
            order.setOrderDetailList(orderDetailMapper.getOrderDetail(order.getId(),null));
            orders.add(order);
        }
        Long total = ordersData.getTotal();
        pageResult.setTotal(total);
        pageResult.setRecords(orders);
        return Result.success(pageResult);
    }

    @Override
    public Result UserCancel(Long orderId) {
        //根据orderId获取订单
        Orders ordersDB = orderMapper.getOrder(orderId,BaseContext.getCurrentId());
        if(ordersDB==null){
            return Result.error(MessageConstant.ORDER_NOT_FOUND);
        }
        //调用mapper将订单设置已取消
        Orders orders = Orders.builder()
                .id(ordersDB.getId())
                .status(Orders.CANCELLED)
                .cancelReason(ordersDB.getCancelReason())
                .cancelTime(LocalDateTime.now())
                .build();
        orderMapper.update(orders);
        return Result.success();
    }

    @Override
    public Result<PageResult> conditionSearch(OrdersPageQueryDTO ordersPageQueryDTO) {
        //获取前端分页数据
        int page = ordersPageQueryDTO.getPage();
        int pageSize = ordersPageQueryDTO.getPageSize();
        //开始分页
        PageHelper.startPage(page,pageSize);
        //获取前端请求下单时间范围
        LocalDateTime beginTime = ordersPageQueryDTO.getBeginTime();
        LocalDateTime endTime = ordersPageQueryDTO.getEndTime();
        //获取订单菜品信息
        List<OrderVO> orderVOS=new ArrayList<>();
        //调用mapper获取数据库订单数据
        Orders wapper=Orders.builder()
                .number(ordersPageQueryDTO.getNumber())
                .phone(ordersPageQueryDTO.getPhone())
                .status(ordersPageQueryDTO.getStatus())
                .build();
        Page<OrderVO> orderVOSdata=orderMapper.getOrdersTimeRange(wapper,beginTime,endTime);
        for (OrderVO orderVO : orderVOSdata.getResult()) {
            List<OrderDetail> orderDetail = orderDetailMapper.getOrderDetail(orderVO.getId(), null);
            orderVO.setOrderDetailList(orderDetail);
            String orderDish="";
            for (OrderDetail detail : orderDetail) {
                orderDish=orderDish+detail.getName()+"* "+detail.getNumber()+";";
            }
            orderVO.setOrderDishes(orderDish);
            orderVOS.add(orderVO);
        }
        long total = orderVOSdata.getTotal();
        PageResult pageResult=new PageResult();
        pageResult.setTotal(total);
        pageResult.setRecords(orderVOS);
        return Result.success(pageResult);
    }

    @Override
    public Result<OrderStatisticsVO> statistics() {

        //待接单数量
        Integer toBeConfirmed=orderMapper.getOrderStatusCount(Orders.TO_BE_CONFIRMED);
        //待派送数量
        Integer confirmed=orderMapper.getOrderStatusCount(Orders.CONFIRMED);
        //派送中数量
        Integer deliveryInProgress=orderMapper.getOrderStatusCount(Orders.DELIVERY_IN_PROGRESS);
        //调用mapper获取各个订单的不同订单状态的数量
        OrderStatisticsVO orderStatistics=OrderStatisticsVO
                .builder()
                .toBeConfirmed(toBeConfirmed)
                .confirmed(confirmed)
                .deliveryInProgress(deliveryInProgress)
                .build();
        return Result.success(orderStatistics);
    }

    @Override
    public Result AdminCancel(OrdersCancelDTO ordersCancelDTO) {
        //根据orderId获取订单
        Orders ordersDB = orderMapper.getOrder(ordersCancelDTO.getId(),BaseContext.getCurrentId());
        if(ordersDB==null){
            return Result.error(MessageConstant.ORDER_NOT_FOUND);
        }
        //调用mapper将订单设置已取消
        Orders orders = Orders.builder()
                .id(ordersDB.getId())
                .status(Orders.CANCELLED)
                .cancelReason(ordersCancelDTO.getCancelReason())
                .cancelTime(LocalDateTime.now())
                .build();
        orderMapper.update(orders);
        return Result.success();
    }

    /**
     * 商家接单其实就是将订单的状态修改为“已接单”
     * @param ordersConfirmDTO
     * @return
     */
    @Override
    public Result confirm(OrdersConfirmDTO ordersConfirmDTO) {
        //根据orderId获取订单
        Orders ordersDB = orderMapper.getOrder(ordersConfirmDTO.getId(),BaseContext.getCurrentId());
        if(ordersDB==null){
            return Result.error(MessageConstant.ORDER_NOT_FOUND);
        }
        //调用mapper将订单设置已接单
        Orders orders = Orders.builder()
                .id(ordersDB.getId())
                .status(Orders.CONFIRMED)
                .build();
        orderMapper.update(orders);
        return Result.success();
    }

    @Override
    public Result rejection(OrdersRejectionDTO ordersRejectionDTO) {
        //根据请求数据获取订单
        Orders ordersDB = orderMapper.getOrder(ordersRejectionDTO.getId(),BaseContext.getCurrentId());
        if(ordersDB==null){
            return Result.error(MessageConstant.ORDER_NOT_FOUND);
        }
        //订单拒单必须保证订单为待接单状态
        if(!Objects.equals(ordersDB.getStatus(), Orders.TO_BE_CONFIRMED)){
            //如果不是待接单状态返回订单状态错误
            return Result.error(MessageConstant.ORDER_STATUS_ERROR);
        }
        //TODO:为用户退款并将订单状态更改为已取消
        Orders order=Orders
                .builder()
                .id(ordersDB.getId())
                .status(Orders.CANCELLED) //订单设置已取消
                .payStatus(Orders.REFUND) //支付状态设置退款
                .cancelReason(ordersRejectionDTO.getRejectionReason())
                .cancelTime(LocalDateTime.now())
                .rejectionReason(ordersRejectionDTO.getRejectionReason()) //设置拒单原因
                .build();
        orderMapper.update(order);
        return Result.success();
    }

    @Override
    public Result delivery(Long orderId) {
        //根据请求数据获取订单
        Orders ordersDB = orderMapper.getOrder(orderId,BaseContext.getCurrentId());
        if(ordersDB==null){
            return Result.error(MessageConstant.ORDER_NOT_FOUND);
        }
        //只有待派送的订单才能派送
        if(!Objects.equals(ordersDB.getStatus(), Orders.CONFIRMED)){
            return Result.error(MessageConstant.ORDER_STATUS_ERROR);
        }
        //将订单设置为派送中
        Orders order=Orders
                .builder()
                .id(ordersDB.getId())
                .status(Orders.DELIVERY_IN_PROGRESS)
                .build();
        orderMapper.update(order);
        return Result.success();
    }

    @Override
    public Result complete(Long orderId) {
        //根据请求数据获取订单
        Orders ordersDB = orderMapper.getOrder(orderId,BaseContext.getCurrentId());
        if(ordersDB==null){
            return Result.error(MessageConstant.ORDER_NOT_FOUND);
        }
        //只有待派送的订单才能派送
        if(!Objects.equals(ordersDB.getStatus(), Orders.DELIVERY_IN_PROGRESS)){
            return Result.error(MessageConstant.ORDER_STATUS_ERROR);
        }

        //将订单设置为已完成
        Orders order=Orders
                .builder()
                .id(ordersDB.getId())
                .deliveryTime(LocalDateTime.now())
                .status(Orders.COMPLETED)
                .build();
        orderMapper.update(order);
        //获取订单送达时间
        order = orderMapper.getOrder(orderId,BaseContext.getCurrentId());
        //送达时间超过预计送达实际则为超时
        Duration dur= Duration.between(order.getDeliveryTime(),ordersDB.getEstimatedDeliveryTime());
        log.info("预计送达时间和实际送达实际相差:{}",dur);
        if(dur.toHours()<0){
            log.info("订单超时{}小时{}分钟",Math.abs(dur.toHours()),Math.abs(dur.toHours())*60-dur.toMinutes());
        }
        return Result.success();
    }

}
